package org.lazycoder.logger.iface;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.UIManager;

import org.lazycoder.logger.EventLogger;
import org.lazycoder.logger.InvalidDatabase;
import org.lazycoder.logger.Module;
import org.lazycoder.logger.Reporter;
import org.lazycoder.logger.module.Journal;
import org.lazycoder.logger.module.ask3.ASK3;

/**
 * @author Matthew Bayliss
 * 
 */
public class SwingMain {

	private class ActionAbout extends AbstractAction {
		private static final long serialVersionUID = -3402498593574284307L;

		public ActionAbout() {
			putValue(NAME, "About");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
		}
	}

	private class ActionClose extends AbstractAction {
		private static final long serialVersionUID = 5167788396634820159L;

		public ActionClose() {
			putValue(NAME, "Close");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			killModules();
			updateSched.shutdown();
			logger.close();
		}
	}

	private class ActionJournal extends AbstractAction {
		private static final long serialVersionUID = 9219079890453978016L;

		public ActionJournal() {
			putValue(NAME, "Journal");
			putValue(SHORT_DESCRIPTION, "Enter an item into the journal.");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			String message = txtJournal.getText().trim();
			txtJournal.setText("");
			if (!message.isEmpty()) {
				Journal.getInstance().log(message);
			}
		}
	}

	private class ActionNew extends AbstractAction {
		private static final long serialVersionUID = -5381804024987193873L;

		public ActionNew() {
			putValue(NAME, "New");
			putValue(SHORT_DESCRIPTION, "Create a new database");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			actionClose.actionPerformed(null);
			JFileChooser jf = new JFileChooser();
			if (jf.showSaveDialog(frmLazylogger) == JFileChooser.APPROVE_OPTION) {
				String dbpath = jf.getSelectedFile().getAbsolutePath();
				logger.create(dbpath);
				updateSched = Executors.newSingleThreadScheduledExecutor();
				updateSched.scheduleAtFixedRate(update, 1, 2, TimeUnit.SECONDS);
				initModules();
			}
		}
	}

	private class ActionOpen extends AbstractAction {
		private static final long serialVersionUID = -8676552493786677783L;

		public ActionOpen() {
			putValue(NAME, "Open");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			actionClose.actionPerformed(null);
			JFileChooser jf = new JFileChooser();
			jf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			jf.setMultiSelectionEnabled(false);

			if (jf.showOpenDialog(frmLazylogger) == JFileChooser.APPROVE_OPTION) {
				try {
					String dbpath = jf.getSelectedFile().getAbsolutePath();
					logger.open(dbpath);
					updateSched = Executors.newSingleThreadScheduledExecutor();
					updateSched.scheduleAtFixedRate(update, 1, 2,
							TimeUnit.SECONDS);
					initModules();
				} catch (InvalidDatabase e1) {
					JOptionPane
							.showMessageDialog(
									frmLazylogger,
									"The database you selected does not appear to be valid. Please try another.  ",
									"Invalid Database",
									JOptionPane.ERROR_MESSAGE);
				}
			}

		}
	}

	private class ActionReport extends AbstractAction {
		private static final long serialVersionUID = 6189193167371034130L;

		public ActionReport() {
			putValue(NAME, "Report");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			Reporter reporter = new Reporter();
			executor.execute(reporter);
		}
	}

	private class Update implements Runnable {
		@Override
		public void run() {
			tblModel.update();
		}
	}

	/**
	 * Launch the application.
	 * 
	 * @param args
	 *            No arguments
	 */
	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Throwable e) {
			e.printStackTrace();
		}
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					SwingMain window = new SwingMain();
					window.frmLazylogger.setVisible(true);
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	private final EventLogger logger;

	private JFrame frmLazylogger;

	private final Action actionAbout = new ActionAbout();

	private final Action actionReport = new ActionReport();
	private final Action actionNew = new ActionNew();
	private final Action actionOpen = new ActionOpen();
	private final Action actionClose = new ActionClose();
	private final Action actionJournal = new ActionJournal();

	private JTable table;
	private final SwingTableModel tblModel;
	private ScheduledExecutorService updateSched;
	private final ExecutorService executor;
	private final Update update;
	private JTextArea txtJournal;

	private final Map<String, Module> modules;

	/**
	 * Create the application.
	 */
	public SwingMain() {
		modules = new HashMap<String, Module>();
		logger = EventLogger.getInstance();
		tblModel = new SwingTableModel();
		updateSched = Executors.newSingleThreadScheduledExecutor();
		update = new Update();
		executor = Executors.newCachedThreadPool();
		initialize();

	}

	/**
	 * 
	 */
	public void initModules() {
		Module m = new ASK3();
		modules.put(m.getName(), m);
		tblModel.setTable(logger.getEvents());
	}

	/**
	 * 
	 */
	public void killModules() {
		Iterator<String> itr = modules.keySet().iterator();
		while (itr.hasNext()) {
			modules.get(itr.next()).stop();
		}
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmLazylogger = new JFrame();
		frmLazylogger.getContentPane().getLayout();
		frmLazylogger.setTitle("LazyLogger");
		frmLazylogger.setBounds(100, 100, 450, 300);
		frmLazylogger.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		final JMenuBar menuBar = new JMenuBar();
		frmLazylogger.setJMenuBar(menuBar);

		final JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);

		mnFile.add(actionNew);

		mnFile.add(actionOpen);

		final JSeparator separator = new JSeparator();
		mnFile.add(separator);

		mnFile.add(actionClose);

		final JMenu mnReport = new JMenu("Report");
		menuBar.add(mnReport);

		mnReport.add(actionReport);

		final JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);

		mnHelp.add(actionAbout);

		final JToolBar toolBar = new JToolBar();
		frmLazylogger.getContentPane().add(toolBar, BorderLayout.NORTH);

		final JButton btnNew = new JButton("New button");
		btnNew.setAction(actionNew);
		toolBar.add(btnNew);

		final JButton btnOpen = new JButton("New button");
		btnOpen.setAction(actionOpen);
		toolBar.add(btnOpen);

		final JButton btnReport = new JButton("New button");
		btnReport.setAction(actionReport);
		toolBar.add(btnReport);

		final JPanel panel = new JPanel();
		frmLazylogger.getContentPane().add(panel, BorderLayout.SOUTH);
		panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));

		final JScrollPane scrollJournal = new JScrollPane();
		panel.add(scrollJournal);

		txtJournal = new JTextArea();
		txtJournal.setRows(2);
		txtJournal.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent arg0) {
				if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
					actionJournal.actionPerformed(null);
				}
			}
		});
		scrollJournal.setViewportView(txtJournal);
		txtJournal.setWrapStyleWord(true);
		txtJournal.setLineWrap(true);

		final JButton btnJournal = new JButton("New button");
		btnJournal.setAction(actionJournal);
		panel.add(btnJournal);

		final JScrollPane scrollPane = new JScrollPane();
		frmLazylogger.getContentPane().add(scrollPane, BorderLayout.CENTER);

		table = new JTable();
		table.setModel(tblModel);
		table.setFillsViewportHeight(true);
		scrollPane.setViewportView(table);
	}
}
